/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pigx.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.enums.AbnormalEnum;
import com.pig4cloud.pigx.common.customize.enums.CommonDictEnum;
import com.pig4cloud.pigx.common.customize.exception.DuckweedException;
import com.pig4cloud.pigx.common.customize.mysql.utils.MysqlUtil;
import com.pig4cloud.pigx.common.customize.security.utils.SecurityUtil;
import com.pig4cloud.pigx.common.customize.utils.id.IdWorker;
import com.pig4cloud.pigx.common.security.service.PigxUser;
import com.pig4cloud.pigx.user.constant.WalletConstant;
import com.pig4cloud.pigx.user.dto.UpdateCapitalAccountDTO;
import com.pig4cloud.pigx.user.entity.*;
import com.pig4cloud.pigx.user.enums.FuelReceiveDividendsEnums;
import com.pig4cloud.pigx.user.enums.RechargeRecordEnum;
import com.pig4cloud.pigx.user.mapper.CapitalAccountMapper;
import com.pig4cloud.pigx.user.service.CapitalAccountService;
import com.pig4cloud.pigx.user.service.RechargeRecordService;
import com.pig4cloud.pigx.user.vo.LoginUserCapitalVO;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 资金账户
 *
 * @author pigx code generator
 * @date 2022-11-21 17:40:27
 */
@AllArgsConstructor
@Service
public class CapitalAccountServiceImpl extends ServiceImpl<CapitalAccountMapper, CapitalAccount> implements CapitalAccountService {

	private final MysqlUtil mysqlUtil;

	private final RechargeRecordService rechargeRecordService;

	private final IdWorker idWorker;

	/**
	 * 为用户生成资金账户
	 * @param user 用户
	 */
	@Override
	public void createCapital(User user) {
		try {
			Long count = baseMapper.selectCount(new QueryWrapper<CapitalAccount>() {{
				eq("user_id", user.getId());
			}});
			if (count > 0) {
				return;
			}
			// 默认只生成UNT账户
			CapitalAccount account = new CapitalAccount();
			account.setId(idWorker.nextId());
			account.setUserId(user.getId());
			account.setFrozen(BigDecimal.ZERO);
			account.setBalance(BigDecimal.ZERO);
			account.setCurrency(WalletConstant.USDT);
			account.setContributionValue(BigDecimal.ZERO);
			baseMapper.insert(account);
		} catch (Exception e) {
			e.printStackTrace();
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED);
		}
	}

	/**
	 * 获取当前登录用户的资金账户
	 * @return
	 */
	@Override
	public R<LoginUserCapitalVO> getUserCapital() {
		PigxUser user = SecurityUtil.getLoginUser();
		if (user == null) {
			throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND);
		}
		try {
			CapitalAccount selectOne = baseMapper.selectOne(new QueryWrapper<CapitalAccount>() {{
				eq("user_id", user.getId());
				select("balance","frozen","currency","contribution_value");
			}});
			if (selectOne == null) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getCode(),"该用户未开通资金账户");
			}
			LoginUserCapitalVO vo = new LoginUserCapitalVO();
			BeanUtils.copyProperties(selectOne,vo);
			// 总资产
			vo.setBalance(vo.getBalance().setScale(3, RoundingMode.DOWN));
			vo.setFrozen(vo.getFrozen().setScale(3, RoundingMode.DOWN));
			vo.setAllBalance((vo.getBalance().add(vo.getFrozen())).setScale(3, RoundingMode.DOWN));
			// 查询累计充值和累计奖励
			RechargeRecord rechargeRecord = new RechargeRecord().selectOne(new QueryWrapper<RechargeRecord>() {{
				eq("user_id", user.getId());
				in("type", RechargeRecordEnum.Type.CHAIN_RECHARGE.getValue(),RechargeRecordEnum.Type.USER_RECHARGE.getValue());
				eq("state", RechargeRecordEnum.Status.SUCCESS.getValue());
				select("sum(quantity) 'quantity'");
			}});
			vo.setRechargeBalance(rechargeRecord != null ? rechargeRecord.getQuantity() : BigDecimal.ZERO);
			RechargeRecord record = new RechargeRecord().selectOne(new QueryWrapper<RechargeRecord>() {{
				eq("user_id", user.getId());
				notIn("type", RechargeRecordEnum.Type.CHAIN_RECHARGE.getValue(),RechargeRecordEnum.Type.USER_RECHARGE.getValue());
				eq("state", RechargeRecordEnum.Status.SUCCESS.getValue());
				select("sum(quantity) 'quantity'");
			}});
			vo.setRewardBalance(record != null ? record.getQuantity() : BigDecimal.ZERO);
			return R.ok(vo);
		} catch (Exception e) {
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED);
		}
	}

	@Override
	public R<String> updateByAdmin(UpdateCapitalAccountDTO dto) {
		try {
			if (dto.getBalance() == null) {
				throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN.getCode(),"充值账户余额不能为空");
			}
			if (dto.getFrozen() == null) {
				throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN.getCode(),"奖励账户余额不能为空");
			}
			if (dto.getContributionValue() == null) {
				throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN.getCode(),"贡献值不能为空");
			}
			mysqlUtil.startLocalTx();
			CapitalAccount one = baseMapper.selectOne(new QueryWrapper<CapitalAccount>() {{
				eq("id", dto.getId());
				last("for update");
			}});
			if (one == null) {
				throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN.getCode(),"用户资金账户不存在");
			}
			// 更新贡献值
			if (dto.getContributionValue() != null) {
				one.setContributionValue(dto.getContributionValue());
			}
			// 本次人工充值变更数量
			BigDecimal balanceSubtract = dto.getBalance().subtract(one.getBalance());
			one.setBalance(dto.getBalance());
			if (balanceSubtract.compareTo(BigDecimal.ZERO) != 0) {
				// 发生资金变动必须填写备注
				if (dto.getRemark() == null) {
					throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN.getCode(),"人工充值必须填写备注信息!");
				}
				// 新增人工充值记录
				RechargeRecord record = new RechargeRecord();
				record.setId(idWorker.nextId());
				record.setUserId(one.getUserId());
				// 人工充值
				record.setType(RechargeRecordEnum.Type.USER_RECHARGE.getValue());
				record.setQuantity(balanceSubtract);
				// 已完成
				record.setState(RechargeRecordEnum.Status.SUCCESS.getValue());
				record.setCurrency(one.getCurrency());
				// 备注
				record.setRemark(dto.getRemark());
				rechargeRecordService.save(record);
			}
			// 本次人工奖励变更数量
			BigDecimal frozenSubtract = dto.getFrozen().subtract(one.getFrozen());
			one.setFrozen(dto.getFrozen());
			if (frozenSubtract.compareTo(BigDecimal.ZERO) != 0) {
				// 发生资金变动必须填写备注
				if (dto.getRemark() == null) {
					throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN.getCode(),"人工充值必须填写备注信息!");
				}
				// 新增人工充值记录
				RechargeRecord record = new RechargeRecord();
				record.setId(idWorker.nextId());
				record.setUserId(one.getUserId());
				// 人工充值
				record.setType(RechargeRecordEnum.Type.REWARD_RECHARGE.getValue());
				record.setQuantity(frozenSubtract);
				// 已完成
				record.setState(RechargeRecordEnum.Status.SUCCESS.getValue());
				record.setCurrency(one.getCurrency());
				// 备注
				record.setRemark(dto.getRemark());
				rechargeRecordService.save(record);
				FuelReceiveDividends dividends = new FuelReceiveDividends() {{
					setId(idWorker.nextId());
					setFuelConsumeId(record.getId());
					setFuelQuantity(frozenSubtract);
					setUserId(one.getUserId());
					setType(FuelReceiveDividendsEnums.Type.REWARD_RECHARGE.getValue());
					setIsSuccess(CommonDictEnum.YesOrNo.YES.getValue());
				}};
				dividends.insert();
			}
			baseMapper.updateById(one);
			// 本次人工充值的数量
			mysqlUtil.commitLocalTx();
			return R.ok("人工充值成功");
		} catch (DuckweedException e) {
			mysqlUtil.rollbackLocalTx();
			throw e;
		} catch (Exception e) {
			mysqlUtil.rollbackLocalTx();
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED);
		}
	}

	@Override
	public void rechargeThen(RechargeRecord record) {
		try {
			mysqlUtil.startLocalTx();
			// 获取资金账户
			CapitalAccount capitalAccount = baseMapper.selectOne(new QueryWrapper<CapitalAccount>() {{
				eq("user_id", record.getUserId());
				last("for update");
			}});
			if (capitalAccount != null) {
				// 本次充值数量 (扣除手续费 - 计算精度)
				BigDecimal bigDecimal = record.getQuantity().setScale(record.getQuantity().scale(), RoundingMode.DOWN);
				// 修改资金账户余额
				capitalAccount.setBalance(capitalAccount.getBalance().add(bigDecimal));
				baseMapper.updateById(capitalAccount);
			}
			mysqlUtil.commitLocalTx();
		} catch (Exception e) {
			log.error("修改资金账户失败");
			mysqlUtil.rollbackLocalTx();
			throw e;
		}
	}

	/**
	 * 获取用户资金账户
	 * @param userId 用户id
	 * @param currency 币种
	 * @return 账户信息
	 */
	@Override
	public CapitalAccount getUserBalance(Long userId,String currency) {
		try {
			CapitalAccount account = baseMapper.selectOne(new QueryWrapper<CapitalAccount>() {{
				eq("user_id", userId);
				eq("currency", currency);
			}});
			if (account == null) {
				throw new Exception();
			}
			return account;
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 获取用户资金账户
	 * @param list 用户id
	 * @param currency 币种
	 * @return 账户信息
	 */
	@Override
	public List<CapitalAccount> getUserBalance(List<User> list, String currency) {
		try {
			// 提取用户id
			List<Long> longs = list.stream().map(User::getId).collect(Collectors.toList());
			List<CapitalAccount> account = baseMapper.selectList(new QueryWrapper<CapitalAccount>() {{
				in("user_id", longs);
				eq("currency", currency);
			}});
			if (account == null) {
				throw new Exception();
			}
			return account;
		} catch (Exception e) {
			return null;
		}
	}

	@Override
	public void updateBalance(Long userId,String currency,BigDecimal balance,boolean isAdd,boolean isFrozen) {
		try {
			CapitalAccount account = baseMapper.selectOne(new QueryWrapper<CapitalAccount>() {{
				eq("user_id", userId);
				eq("currency", currency);
				last("for update");
			}});
			if (account == null) {
				throw new DuckweedException(AbnormalEnum.MSG.OPTIONS_USER_NOT_FOUND.getCode(),"该用户未开通资金账户");
			}
			BigDecimal change;
			if (isAdd) {
				if (isFrozen) {
					change = account.getFrozen().add(balance);
				} else {
					change = account.getBalance().add(balance);
				}
			} else {
				if (isFrozen) {
					change = account.getFrozen().subtract(balance);
				} else {
					change = account.getBalance().subtract(balance);
				}
			}
			if (isFrozen) {
				account.setFrozen(change);
			} else {
				account.setBalance(change);
			}
			baseMapper.updateById(account);
		} catch (DuckweedException e) {
			throw e;
		} catch (Exception e) {
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED.getCode(),"修改资金账户失败");
		}
	}
}
